﻿using Qing.Lang;
using Qing.Std;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Qing.Proto {
    class CreateHashSetObj : Native {
        public override string Name { get; set; } = "创建哈希集";
        public override string Desc { get; set; } = "参数1-数组，返回哈希集对象；创建哈希集";
        public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {
            HashSetObj set = new HashSetObj();
            if (args.Count > 0 && args[0].Tp == TP.Arr) {
                foreach(var item in args[0].List!) {
                    set.Add(item);
                }
            }

            return new Expr(TP.Obj, set);
        }
    }


    public class HashSetObj : Obj {

        public HashSetObj() {
            Raw = new Dictionary<string,Expr>();

            Map["@添加"] = new Expr(new SetAdd());
            Map["@删除"] = new Expr(new SetRemove());
            Map["@包含"] = new Expr(new SetContains());
            Map["@数量"] = new Expr(new SetCount());
            Map["@转数组"] = new Expr(new Set2Arr());
        }


        public static string Expr2Key(Expr key) {
            string k = key.Tp.ToString();
            switch (key.Tp) {
                case TP.None:
                case TP.Bool:
                case TP.Int:
                case TP.Float:
                case TP.Bin:
                case TP.Arr:
                    k += key.ToStr();
                    break;

                case TP.Str:
                    k += key.Str();
                    break;

                default:
                    k += key.Val.GetHashCode();
                    break;
            }

            return k;
        }

        public int Add(Expr val) {
            string k = Expr2Key(val);

            Dictionary<string, Expr> set = (Dictionary<string, Expr>)Raw;
            bool haskey = set.ContainsKey(k);
            if (haskey) {
                return 0;
            } else {
                set[k] = val.Dup();
                return 1;
            }
        }

        public Expr GetOrDefault(Expr key, Expr? def = null) {
            string k = Expr2Key(key);

            Dictionary<string, Expr> set = (Dictionary<string, Expr>)Raw;
            if (set.ContainsKey(k)) {
                return set[k];
            } else {
                if(def == null) {
                    return Expr.NoneExpr;
                }
                return def;
            }

        }

        public bool ContainsKey(Expr key) {
            string k = Expr2Key(key);

            Dictionary<string, (Expr, Expr)> set = (Dictionary<string, (Expr, Expr)>)Raw;
            return set.ContainsKey(k);
        }


        class SetAdd : Native {
            public override string Name { get; set; } = "添加";
            public override string Desc { get; set; } = "参数1-任意，返回整数；将参数1对应的值添加到哈希集中，若已存在返回0，否则返回1";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {
                HashSetObj set = (HashSetObj)obj!;
                if(args.Count < 1) {
                    return Expr.Err("哈希集@添加 函数需要至少1个参数");
                }

                return new Expr(TP.Int, set.Add(args[0]));

            }
        }

        class SetRemove : Native {
            public override string Name { get; set; } = "删除";
            public override string Desc { get; set; } = "参数1-任意，返回整数；从哈希集中删除参数1对应的值，若值存在返回1，否则返回0";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {

                if (args.Count < 1) {
                    return Expr.Err("哈希表@包含 函数需要至少1个参数");
                }

                Dictionary<string, Expr> set = (Dictionary<string, Expr>)obj!.Raw;
                string k = HashSetObj.Expr2Key(args[0]);
                if (set.ContainsKey(k)) {
                    set.Remove(k);
                    return new Expr(TP.Int, 1);
                } else {
                    return new Expr(TP.Int, 0);
                }

            }
        }

        class SetContains : Native {
            public override string Name { get; set; } = "包含";
            public override string Desc { get; set; } = "参数1-任意，返回逻辑；参数1作为键，判断哈希集是否包含键";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {

                if (args.Count < 1) {
                    return Expr.Err("哈希表@包含 函数需要至少1个参数");
                }

                Dictionary<string, Expr> set = (Dictionary<string, Expr>)obj!.Raw;
                return new Expr(TP.Bool, set.ContainsKey(HashSetObj.Expr2Key(args[0])));

            }
        }

        class SetCount : Native {
            public override string Name { get; set; } = "数量";
            public override string Desc { get; set; } = "无参，返回整数；返回哈希集中值的数量";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {

                Dictionary<string, Expr> set = (Dictionary<string, Expr>)obj!.Raw;
                return new Expr(TP.Int, set.Count);

            }
        }

        class Set2Arr : Native {
            public override string Name { get; set; } = "转数组";
            public override string Desc { get; set; } = "无参，返回数组；将哈希集转为数组";
            public override Expr Run(List<Expr> args, Ctx ctx, Obj? obj = null, List<Expr>? namedArgs = null) {

                Dictionary<string, Expr> set = (Dictionary<string, Expr>)obj!.Raw;

                List<Expr> list = new List<Expr>();
                foreach(var item in set.Values) {
                    list.Add(item);
                }

                return new Expr(TP.Arr, 0, list);
            }
        }


    }
}
